<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>

    <div id="app" style="width: 900px;height: 453px;margin: 20px;border: 1px solid #ccc;position: relative;">
        <div id="dr" style="width: 100px; height: 100px; background-color: rgb(51, 51, 51); position: absolute; top: 149px; left: 149px;">
            <div id="handle" style="width:20px;height:20px;background-color:#999">
            </div>
        </div>
    </div>
    <script>
        function DrapBox(o) {
            if (!o.rangeBox || !o.elem) return;
            this._rangeBox = o.rangeBox;
            this._elem = o.elem;
            if (!this._rangeBox.style.position) this._rangeBox.style.position = 'relative';
            this._elem.style.position = "absolute"
            this._handle = o.handle ? o.handle : this._elem;
            this._handle.style.cursor = "move";
            var _this = this;
            this._handle.addEventListener("mousedown", function (event) {
                _this.startDrap(event);
            }, false);
            this._lockX = o.lockX || false;
            this._lockY = o.lockY || false;
        }
        DrapBox.prototype = {
            startDrap(event) {
                var fastpot = this.getPot();
                var x1 = fastpot.x - this._rangeBox.offsetLeft - this._elem.offsetLeft;//初始时鼠标相对dom坐标
                var y1 = fastpot.y - this._rangeBox.offsetTop - this._elem.offsetTop;//初始时鼠标相对dom坐标
                var _this = this;
                function mousemoveHandle(event) {
                    var pot = _this.getPot();//先获取鼠标坐标排除滚动条 
                    var disX = pot.x - _this._rangeBox.offsetLeft;//排除容器边距
                    var disY = pot.y - _this._rangeBox.offsetTop;//排除容器边距
                    var x = disX - x1;
                    var y = disY - y1;
                    var range = {
                        minX: _this._rangeBox.scrollLeft,//最小横坐标范围
                        minY: _this._rangeBox.scrollTop,//最小纵坐标范围
                        maxX: _this._rangeBox.scrollWidth - _this._elem.offsetWidth,//最大横坐标
                        maxY: _this._rangeBox.scrollHeight - _this._elem.offsetHeight//最大纵坐标
                    };
                    x = Math.max(x, range.minX);
                    x = Math.min(x, range.maxX);
                    y = Math.max(y, range.minY);
                    y = Math.min(y, range.maxY); 
                    if (true == _this._lockX && true == _this._lockY) {
                    } else if (true == _this._lockX) {
                        _this._elem.style.left = x + "px";
                    } else if (true == _this._lockY) {
                        _this._elem.style.top = y + "px";
                    } else {
                        _this._elem.style.left = x + "px";
                        _this._elem.style.top = y + "px";
                    }
                };

                function mouseupHandle() {
                    document.removeEventListener("mousemove", mousemoveHandle);
                    document.removeEventListener("mouseup", mouseupHandle);
                };
                document.addEventListener("mousemove", mousemoveHandle);
                document.addEventListener("mouseup", mouseupHandle);
            },
            getPot() {
                return {
                    x: event.pageX || event.clientX
                        + document.documentElement.scrollLeft,
                    y: event.pageY || event.clientY
                        + document.documentElement.scrollTop
                };
            }
        };
        new DrapBox({
            rangeBox: document.getElementById("app"),
            elem: document.getElementById("dr"),
            handle:document.getElementById("handle"),
            // lockX:true,
            // lockY:true,
        })
    </script>
</body>

</html>